import { getCurrentInstance, inject, computed, reactive } from "vue";
import { piniaSymbol } from "./piniaSymbol";

/**
 * 三种传参数方式
 * 1. id + options
 * 2. id+ setup
 * 3. options
 */
export function defineStore(idOrOptions, optionsOrSetup) {
  let id, options;
  if (typeof idOrOptions === "string") {
    id = idOrOptions;
    options = optionsOrSetup;
  } else {
    options = idOrOptions;
    id = options.id;
  }
  function useStore() {
    const instance = getCurrentInstance(); // 获取组件实例子
    const piniaStore = instance && inject(piniaSymbol); // 获取pinia
    if (!piniaStore._stores.has(id)) {
      // 没有Id对应的值， 就创建
      if (typeof optionsOrSetup === "function") {
        createSetupStore(id, optionsOrSetup, piniaStore);
      } else {
        createOptionsStore(id, options, piniaStore);
      }
    }

    return piniaStore._stores.get(id);
  }

  return useStore;
}

function createOptionsStore(id, options, piniaStore) {
  const { state, getters, actions } = options;
  function setup() {
    const localState = state ? state() : {};
    // 处理getters
    const obj = Object.keys(getters).reduce((computedGetters, name) => {
      computedGetters[name] = computed(() => {
        let store = piniaStore._stores.get(id);
        return getters[name].call(store, store);
      });
      return computedGetters;
    }, {});
    return Object.assign(localState, actions, obj);
  }
  // piniaStore._stores.set(id, setup());
  createSetupStore(id, setup, piniaStore);
}

function createSetupStore(id, setup, piniaStore) {
  const store = reactive({}); // 响应式数据
  const setupStore = setup();
  for (const key in setupStore) {
    const prop = setupStore[key];
    if (typeof prop === "function") {
      setupStore[key] = wrapAction(prop);
    }
  }

  // 处理this指向
  function wrapAction(action) {
    return function () {
      let ret = action.apply(store, arguments);
      return ret;
    };
  }

  Object.assign(store, setupStore);
  piniaStore._stores.set(id, store);
  return store;
}
